let Vue;

function forEachValue (obj, fn) {
    Object.keys(obj).forEach(function (key) { return fn(obj[key], key); });
}

function partial (fn, arg) {
    return function () {
        return fn(arg)
    }
}

class Store {
  constructor(options) {
    this._vm = new Vue({
      data: {
        $$state: options.state
      },

    })

    this._mutations = options.mutations
    this._actions = options.actions

    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)

    const wrappedGetters = options.getters
    const store = this
    const computed = {}
    forEachValue(wrappedGetters, (fn, key) => {
        computed[key] = partial(fn, store.state)
        Object.defineProperty(store.getters, key, {
          get: () => store._vm[key],
          enumerable: true // for local getters
        })
    })

    store._vm = new Vue({
      data: {
        $$state: options.state
      },
      computed
    })
  }

  get state() {
      return this._vm._data.$$state
  }

  set state(v) {
    console.error("Please use replaceState to reset state")
  }

  commit(type, payload) {
    let entry = this._mutations[type]
    if (!entry) {
        console.error("unknown mutations")
    }
    entry(this.state, payload)
  }

  dispatch(type, payload) {
    let entry = this._actions[type]
    if (!entry) {
        console.error("unknown action method")
    }

    entry(this, payload)
  }


}

function install (_Vue) {
    Vue = _Vue

    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}

export default {Store, install}